"""
调度算法基类
定义统一的调度接口和基础功能
"""

from abc import ABC, abstractmethod
from typing import List, Dict, Any, Tuple
import numpy as np
from datetime import datetime, timedelta

class BaseScheduler(ABC):
    """调度算法基类"""
    
    def __init__(self, config: Dict[str, Any] = None):
        """
        初始化调度器
        
        Args:
            config: 配置参数字典
        """
        self.config = config or {}
        self.resources = []
        self.appointments = []
        self.constraints = []
        
    @abstractmethod
    def optimize(self, 
                 resources: List[Dict], 
                 appointments: List[Dict], 
                 objectives: List[str]) -> Dict[str, Any]:
        """
        执行调度优化
        
        Args:
            resources: 资源列表
            appointments: 预约列表
            objectives: 优化目标列表
            
        Returns:
            调度结果字典
        """
        pass
    
    def validate_constraints(self, solution: Dict[str, Any]) -> bool:
        """
        验证调度方案是否满足约束条件
        
        Args:
            solution: 调度方案
            
        Returns:
            是否满足约束
        """
        # 检查资源冲突
        for resource_id, assignments in solution.get('assignments', {}).items():
            if self._has_time_conflict(assignments):
                return False
                
        # 检查医生可用性
        for doctor_id, schedule in solution.get('doctor_schedules', {}).items():
            if not self._check_doctor_availability(doctor_id, schedule):
                return False
                
        return True
    
    def _has_time_conflict(self, assignments: List[Dict]) -> bool:
        """检查时间冲突"""
        if len(assignments) <= 1:
            return False
            
        # 按开始时间排序
        sorted_assignments = sorted(assignments, key=lambda x: x['start_time'])
        
        for i in range(len(sorted_assignments) - 1):
            current = sorted_assignments[i]
            next_assignment = sorted_assignments[i + 1]
            
            if current['end_time'] > next_assignment['start_time']:
                return True
                
        return False
    
    def _check_doctor_availability(self, doctor_id: str, schedule: Dict) -> bool:
        """检查医生可用性"""
        # 这里应该查询医生的排班信息
        # 简化实现，实际应该查询数据库
        return True
    
    def calculate_objectives(self, solution: Dict[str, Any]) -> Dict[str, float]:
        """
        计算优化目标值
        
        Args:
            solution: 调度方案
            
        Returns:
            目标值字典
        """
        objectives = {}
        
        # 资源利用率
        objectives['resource_utilization'] = self._calculate_resource_utilization(solution)
        
        # 患者等待时间
        objectives['patient_wait_time'] = self._calculate_patient_wait_time(solution)
        
        # 公平性评分
        objectives['fairness'] = self._calculate_fairness(solution)
        
        # 加班成本
        objectives['overtime_cost'] = self._calculate_overtime_cost(solution)
        
        return objectives
    
    def _calculate_resource_utilization(self, solution: Dict[str, Any]) -> float:
        """计算资源利用率"""
        total_utilization = 0
        resource_count = 0
        
        for resource_id, assignments in solution.get('assignments', {}).items():
            if not assignments:
                continue
                
            # 计算该资源的使用时间
            total_time = sum(
                (assignment['end_time'] - assignment['start_time']).total_seconds() / 3600
                for assignment in assignments
            )
            
            # 假设资源每天工作8小时
            daily_capacity = 8
            utilization = min(total_time / daily_capacity, 1.0)
            total_utilization += utilization
            resource_count += 1
            
        return total_utilization / resource_count if resource_count > 0 else 0
    
    def _calculate_patient_wait_time(self, solution: Dict[str, Any]) -> float:
        """计算患者平均等待时间"""
        wait_times = []
        
        for appointment in self.appointments:
            scheduled_time = appointment.get('scheduled_time')
            preferred_time = appointment.get('preferred_time')
            
            if scheduled_time and preferred_time:
                wait_time = abs((scheduled_time - preferred_time).total_seconds() / 60)
                wait_times.append(wait_time)
                
        return np.mean(wait_times) if wait_times else 0
    
    def _calculate_fairness(self, solution: Dict[str, Any]) -> float:
        """计算公平性评分"""
        # 基于预约时间分布的公平性
        appointment_times = []
        for appointment in self.appointments:
            if appointment.get('scheduled_time'):
                appointment_times.append(appointment['scheduled_time'])
                
        if len(appointment_times) < 2:
            return 1.0
            
        # 计算时间间隔的方差，方差越小越公平
        intervals = []
        sorted_times = sorted(appointment_times)
        for i in range(len(sorted_times) - 1):
            interval = (sorted_times[i+1] - sorted_times[i]).total_seconds() / 3600
            intervals.append(interval)
            
        if not intervals:
            return 1.0
            
        variance = np.var(intervals)
        # 将方差转换为0-1的公平性评分
        fairness = 1.0 / (1.0 + variance)
        return fairness
    
    def _calculate_overtime_cost(self, solution: Dict[str, Any]) -> float:
        """计算加班成本"""
        overtime_hours = 0
        
        for resource_id, assignments in solution.get('assignments', {}).items():
            for assignment in assignments:
                # 检查是否超出正常工作时间（假设18:00为下班时间）
                end_time = assignment['end_time']
                if end_time.hour >= 18:
                    overtime_hours += (end_time.hour - 18) + (end_time.minute / 60)
                    
        # 假设每小时加班成本为100元
        return overtime_hours * 100
